﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using PSE.Framework.UI.Resources;
using System.Windows.Threading;
using System.Threading;

namespace Sinacor.Infra.UI.Controls.SmartClient
{
    #region Enums
    #region SinacorMessageBoxButton
    /// <summary>
    /// Tipos de botões que serão exibidos na janela de mensagem
    /// </summary>
    public enum SinacorMessageBoxButton
    {
        Ok = 0,
        OkCancel = 1,
        YesNo = 2,
        YesNoCancel = 3
    }
    #endregion

    #region SinacorMessageBoxResult
    /// <summary>
    /// Valor do botão pressionado pelo usuário na janela de mensagem
    /// </summary>
    public enum SinacorMessageBoxResult
    {
        Ok = 0,
        Cancel = 1,
        Yes = 2,
        No = 3,
        None = 4
    }
    #endregion

    #region SinacorMessageBoxImage
    /// <summary>
    /// Tipos de imagens que serão exibidas na janela de mensagem
    /// </summary>
    public enum SinacorMessageBoxImage
    {
        Error = 0,
        Question = 1,
        Exclamation = 2,
        Information = 3,
        None = 4
    }
    #endregion

    public enum SinacorMessageBoxState
    {
        Opened,
        Closed
    }

    #endregion

    /// <summary>
    /// Componente de Mensagens do sistema Sinacor
    /// </summary>
    public class SinacorMessageBox
    {
        #region Properties
        /// <summary>
        /// Armazenará o valor do botão pressionado pelo usuário
        /// </summary>
        public SinacorMessageBoxResult Retorno { get; set; }

        private const string DEFAULT_TITLE = "Infra.Controls.Label.DefaultMessageBoxTitle";

        #endregion

        #region Constructor
        /// <summary>
        /// Construtor padrão
        /// </summary>
        static SinacorMessageBox()
        {
        }
        #endregion

        #region Static Methods
        /// <summary>
        /// Exibe janela de mensagem
        /// </summary>
        /// <param name="message">Mensagem a ser exibida na janela</param>
        /// <returns>Valor do botão pressionado pelo usuário</returns>
        public static SinacorMessageBoxResult Show(String message)
        {
            return Show(message, DEFAULT_TITLE, SinacorMessageBoxButton.Ok, SinacorMessageBoxImage.None);
        }

        /// <summary>
        /// Exibe janela de mensagem
        /// </summary>
        /// <param name="message">Mensagem que será exibida na janela</param>
        /// <param name="title">Título da janela</param>
        /// <returns>Valor do botão pressionado pelo usuário</returns>
        public static SinacorMessageBoxResult Show(String message, String title)
        {
            return Show(message, title, SinacorMessageBoxButton.Ok, SinacorMessageBoxImage.None);
        }

        /// <summary>
        /// Exibe a janela de mensagem
        /// </summary>
        /// <param name="message">Mensagem que será exibida na janela</param>
        /// <param name="title">Título da janela</param>
        /// <param name="sinacorMessageBoxButton">Conjunto de botões que serão exibidos na janela</param>
        /// <returns>Valor do botão pressionado pelo usuário</returns>
        public static SinacorMessageBoxResult Show(String message, String title, SinacorMessageBoxButton sinacorMessageBoxButton)
        {
            return Show(message, title, sinacorMessageBoxButton, SinacorMessageBoxImage.None);
        }

        /// <summary>
        /// Exibe janela de mensagem
        /// </summary>
        /// <param name="message">Mensagem que será exibida janela</param>
        /// <param name="sinacorMessageBoxButton">Conjunto de botões que serão exibidos na janela</param>
        /// <returns>Valor do botão pressionado pelo usuário</returns>
        public static SinacorMessageBoxResult Show(String message, SinacorMessageBoxButton sinacorMessageBoxButton)
        {
            return Show(message, DEFAULT_TITLE, sinacorMessageBoxButton, SinacorMessageBoxImage.None);
        }

        /// <summary>
        /// Exibe janela de mensagem
        /// </summary>
        /// <param name="message">Mensagem que será exibida na janela</param>
        /// <param name="title">Título da janela</param>
        /// <param name="sinacorMessageBoxImage">Imagem que será exibida na janela</param>
        /// <returns>Valor do botão pressionado pelo usuário</returns>
        public static SinacorMessageBoxResult Show(String message, String title, SinacorMessageBoxImage sinacorMessageBoxImage)
        {
            return Show(message, title, SinacorMessageBoxButton.Ok, sinacorMessageBoxImage);
        }

        /// <summary>
        /// Exibe janela de mensagem
        /// </summary>
        /// <param name="message">Mensagem que será exibida na janela</param>
        /// <param name="sinacorMessageBoxImage">Imagem que será exibida na janela</param>
        /// <returns>Valor do botão pressionado pelo usuário</returns>
        public static SinacorMessageBoxResult Show(String message, SinacorMessageBoxImage sinacorMessageBoxImage)
        {
            return Show(message, DEFAULT_TITLE, SinacorMessageBoxButton.Ok, sinacorMessageBoxImage);
        }

        /// <summary>
        /// Exibe janela de mensagem
        /// </summary>
        /// <param name="message">Mensagem que será exibida na janela</param>
        /// <param name="sinacorMessageBoxButton">Conjunto de botões que serão exibidos na janela</param>
        /// <param name="sinacorMessageBoxImage">Imagem que será exibida na janela</param>
        /// <returns>Valor do botão pressionado pelo usuário</returns>
        public static SinacorMessageBoxResult Show(String message, SinacorMessageBoxButton sinacorMessageBoxButton, SinacorMessageBoxImage sinacorMessageBoxImage)
        {
            return Show(message, DEFAULT_TITLE, sinacorMessageBoxButton, sinacorMessageBoxImage);
        }

        public static SinacorMessageBoxResult Show(String message, String title, SinacorMessageBoxButton sinacorMessageBoxButton, SinacorMessageBoxImage sinacorMessageBoxImage)
        {
            return Show(message, title, sinacorMessageBoxButton, sinacorMessageBoxImage, null, null);
        }

        /// <summary>
        /// Exibe janela de mensagem
        /// </summary>
        /// <param name="message">Mensagem que será exibida na janela</param>
        /// <param name="title">Título da janela</param>
        /// <param name="sinacorMessageBoxButton">Conjunto de botões que serão exibidos na janela</param>
        /// <param name="sinacorMessageBoxImage">Imagem que será exibida na janela</param>
        /// <returns>Valor do botão pressionado pelo usuário</returns>
        public static SinacorMessageBoxResult Show(String message, String title, SinacorMessageBoxButton sinacorMessageBoxButton, SinacorMessageBoxImage sinacorMessageBoxImage, double? windowHeight, double? windowWidth)
        {
            SinacorMessageBoxWindow msg = new SinacorMessageBoxWindow(message, title, sinacorMessageBoxButton, sinacorMessageBoxImage, windowHeight, windowWidth);
            SinacorMessageBoxResult result;

            // Estilo default
            if (msg.Template != null)
            {
                if (msg.Title == DEFAULT_TITLE)
                {
                    msg.Title = (string)ResourceProviderManager.GetResourceProvider().TryGetResource(msg.Title);
                }

                if (OnMessageBoxStateChanged != null)
                    OnMessageBoxStateChanged(SinacorMessageBoxState.Opened);

                System.Windows.Threading.Dispatcher.CurrentDispatcher
                    .Invoke(new Action(delegate() { msg.ShowDialog(); }), null);

                result = msg.Retorno;

                if (OnMessageBoxStateChanged != null)
                    OnMessageBoxStateChanged(SinacorMessageBoxState.Closed);

                msg = null;
            }
            else
            {
                string caption = title;

                if (caption == DEFAULT_TITLE)
                {
                    caption = (string)ResourceProviderManager.GetResourceProvider().TryGetResource(caption);
                }

                MessageBoxButton button;
                switch (sinacorMessageBoxButton)
                {
                    case SinacorMessageBoxButton.Ok:
                        button = MessageBoxButton.OK;
                        break;
                    case SinacorMessageBoxButton.OkCancel:
                        button = MessageBoxButton.OKCancel;
                        break;
                    case SinacorMessageBoxButton.YesNo:
                        button = MessageBoxButton.YesNo;
                        break;
                    case SinacorMessageBoxButton.YesNoCancel:
                        button = MessageBoxButton.YesNoCancel;
                        break;
                    default:
                        button = MessageBoxButton.OK;
                        break;
                }

                MessageBoxImage icon;
                switch (sinacorMessageBoxImage)
                {
                    case SinacorMessageBoxImage.Error:
                        icon = MessageBoxImage.Error;
                        break;
                    case SinacorMessageBoxImage.Question:
                        icon = MessageBoxImage.Question;
                        break;
                    case SinacorMessageBoxImage.Exclamation:
                        icon = MessageBoxImage.Exclamation;
                        break;
                    case SinacorMessageBoxImage.Information:
                        icon = MessageBoxImage.Information;
                        break;
                    case SinacorMessageBoxImage.None:
                        icon = MessageBoxImage.None;
                        break;
                    default:
                        icon = MessageBoxImage.None;
                        break;
                }

                // MessageBox normal
                MessageBoxResult r = MessageBox.Show(message, caption, button, icon);

                switch (r)
                {
                    case MessageBoxResult.OK:
                        result = SinacorMessageBoxResult.Ok;
                        break;
                    case MessageBoxResult.Cancel:
                        result = SinacorMessageBoxResult.Cancel;
                        break;
                    case MessageBoxResult.Yes:
                        result = SinacorMessageBoxResult.Yes;
                        break;
                    case MessageBoxResult.No:
                        result = SinacorMessageBoxResult.No;
                        break;
                    case MessageBoxResult.None:
                        result = SinacorMessageBoxResult.None;
                        break;
                    default:
                        result = SinacorMessageBoxResult.None;
                        break;
                }
            }


            return result;
        }

        /// <summary>
        /// Exibe janela de erro com opção para coleta
        /// </summary>
        /// <param name="message">Mensagem que será exibida na janela</param>
        /// <param name="logData">Log a ser coletado</param>
        /// <param name="owner">Janela que ocorreu o erro</param>
        public static void ShowError(String message, Uri sourceAddress, PSE.Framework.ErrorLogging.LogData logData)
        {
            ShowError(message, DEFAULT_TITLE, sourceAddress, logData, null);
        }

        /// <summary>
        /// Exibe janela de erro com opção para coleta
        /// </summary>
        /// <param name="message">Mensagem que será exibida na janela</param>
        /// <param name="logData">Log a ser coletado</param>
        /// <param name="owner">Janela que ocorreu o erro</param>
        public static void ShowError(String message, Uri sourceAddress, PSE.Framework.ErrorLogging.LogData logData, Window sourceErrorWindow)
        {
            ShowError(message, DEFAULT_TITLE, sourceAddress, logData, sourceErrorWindow);
        }

        /// <summary>
        /// Exibe janela de erro com opção para coleta
        /// </summary>
        /// <param name="message">Mensagem que será exibida na janela</param>
        /// <param name="title">Título da janela</param>
        /// <param name="logData">Log a ser coletado</param>
        /// <param name="owner">Janela que ocorreu o erro</param>
        public static void ShowError(String message, String title, Uri sourceAddress, PSE.Framework.ErrorLogging.LogData logData)
        {
            ShowError(message, title, sourceAddress, logData, null);
        }

        /// <summary>
        /// Exibe janela de erro com opção para coleta
        /// </summary>
        /// <param name="message">Mensagem que será exibida na janela</param>
        /// <param name="title">Título da janela</param>
        /// <param name="logData">Log a ser coletado</param>
        /// <param name="owner">Janela que ocorreu o erro</param>
        public static void ShowError(String message, String title, Uri sourceAddress, PSE.Framework.ErrorLogging.LogData logData, Window sourceErrorWindow)
        {
            if (Thread.CurrentThread == Dispatcher.CurrentDispatcher.Thread)
            {
//#if DEBUG
//                bool debug = true;
//#else
//                bool debug = false;
//#endif
                string displayMessage = null;

                try
                {
                    // Título padrão
                    if (title == DEFAULT_TITLE || string.IsNullOrEmpty(title))
                    {
                        title = (string)ResourceProviderManager.GetResourceProvider().TryGetResource(DEFAULT_TITLE);
                    }

                    if (!Dispatcher.CurrentDispatcher.HasShutdownStarted)
                    {
                        displayMessage = GetDisplayMessage(message, logData, logData != null);

                        SinacorErrorWindow msg = new SinacorErrorWindow(displayMessage, title, sourceAddress, logData);

                        if (sourceErrorWindow != null)
                            msg.Owner = sourceErrorWindow;

                        msg.ShowDialog();
                    }
                    else
                    {
                        displayMessage = GetDisplayMessage(message, logData, false);

                        System.Windows.Forms.Form.CheckForIllegalCrossThreadCalls = false;
                        System.Windows.Forms.MessageBox.Show(displayMessage, title, System.Windows.Forms.MessageBoxButtons.OK, System.Windows.Forms.MessageBoxIcon.Error);
                    }
                }
                catch (Exception ex)
                {
                    if (logData != null)
                    {
                        if (logData.DisplayErrors == null)
                            logData.DisplayErrors = new List<string>();

                        logData.DisplayErrors.Add(ex.ToString());
                    }

                    displayMessage = GetDisplayMessage(message, logData, false);

                    System.Windows.Forms.Form.CheckForIllegalCrossThreadCalls = false;
                    System.Windows.Forms.MessageBox.Show(displayMessage, title, System.Windows.Forms.MessageBoxButtons.OK, System.Windows.Forms.MessageBoxIcon.Error);
                }
            }
            else
            {
                Dispatcher.CurrentDispatcher.Invoke(new ShowErrorDelegate(ShowError), message, title, sourceAddress, logData, sourceErrorWindow);
            }
        }
        private delegate void ShowErrorDelegate(String message, String title, Uri sourceAddress, PSE.Framework.ErrorLogging.LogData logData, Window sourceErrorWindow);

        private static string GetDisplayMessage(string message, PSE.Framework.ErrorLogging.LogData logData, bool showCollectError)
        {
            string displayMessage;

            if (!string.IsNullOrEmpty(message))
                displayMessage = message;
            else
                displayMessage = "Error message not available.";

            if (showCollectError)
                displayMessage += Environment.NewLine + Environment.NewLine + ResourceProviderManager.GetResourceProvider().TryGetResource("Infra.Application.Message.InstrucoesRelatorioErros");

            //// Se estiver no modo DEBUG ou a mensagem estiver vazia, exibe os detalhes da Exception
            //if (logData != null && (debug || string.IsNullOrEmpty(message)))
            //    displayMessage += Environment.NewLine + Environment.NewLine + logData.ToString();

            return displayMessage;
        }
        #endregion

        #region Static Events
        public delegate void OnMessageBoxStateChangedEventHandler(SinacorMessageBoxState state);
        public static event OnMessageBoxStateChangedEventHandler OnMessageBoxStateChanged;
        #endregion
    }
}